package com.example.gaoyang.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.gaoyang.constant.Constant;
import com.example.gaoyang.domain.SysElement;
import com.example.gaoyang.domain.request.SysElementRequest;
import com.example.gaoyang.domain.vo.SysElementVO;
import com.example.gaoyang.enums.ResultEnum;
import com.example.gaoyang.exception.InvalidParameterException;
import com.example.gaoyang.mapper.SysElementMapper;
import com.example.gaoyang.request.Result;
import com.example.gaoyang.service.SysElementService;
import com.example.gaoyang.util.ResultUtil;
import com.example.gaoyang.wrapper.SysElementWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Slf4j
@Service
@Transactional
public class SysElementServiceImpl extends ServiceImpl<SysElementMapper, SysElement> implements SysElementService {
    @Override
    public void addSysElement(SysElementRequest sysElementRequest) {
        // 父节点id不能为空
        Long parentId = sysElementRequest.getParentId();
        if (parentId == null) {
            throw new InvalidParameterException("参数parentId缺失");
        }
        // 元素类型必填
        Integer elementType = sysElementRequest.getElementType();
        if (elementType == null) {
            throw new InvalidParameterException("参数elementType缺失");
        }
        SysElement sysElement = BeanUtil.copyProperties(sysElementRequest, SysElement.class);
        sysElement.setId(IdUtil.getSnowflake().nextId());
        sysElement.setCreateTime(new Date());
        this.save(sysElement);
    }

    @Override
    public void removeSysElement(SysElementRequest sysElementRequest) {
        // id不能为空
        Long id = sysElementRequest.getId();
        if (id == null) {
            throw new InvalidParameterException("参数id缺失");
        }
        // 如果这个元素有子节点则需要全部删除
        List<SysElement> childElements = this.getLinkChildElementById(id);
        if (CollectionUtil.isEmpty(childElements)) {
            throw new InvalidParameterException(String.format("系统元素不存在,系统元素id:[%s]", id));
        }
        this.removeBatchByIds(childElements);
    }

    @Override
    public List<SysElementVO> getSysElementList(SysElementRequest sysElementRequest) {
        LambdaQueryWrapper<SysElement> wrapper = this.createWrapper(sysElementRequest);
        List<SysElement> list = this.list(wrapper);
        return BeanUtil.copyToList(list, SysElementVO.class);
    }

    @Override
    public IPage<SysElementVO> getSysElementPage(IPage<SysElement> page, SysElementRequest sysElementRequest) {
        page.setCurrent(sysElementRequest.getPageNum());
        page.setSize(sysElementRequest.getPageSize());
        // 请注意:SQL server在分页查询时，需要先排序
        return new SysElementWrapper().pageVO(this.page(page, this.createWrapper(sysElementRequest)));
    }

    @Override
    public void updateSysElement(SysElementRequest sysElementRequest) {
        // id不能为空
        Long id = sysElementRequest.getId();
        if (id == null) {
            throw new InvalidParameterException("参数id缺失");
        }
        SysElement sysElement = BeanUtil.copyProperties(sysElementRequest, SysElement.class);
        sysElement.setUpdateTime(new Date());
        this.updateById(sysElement);
    }

    @Override
    public List<SysElementVO> getAllElementTree() {
        List<SysElement> elements = this.list();
        List<SysElementVO> rootNodes = this.buildElementTree(BeanUtil.copyToList(elements, SysElementVO.class));
        return rootNodes;
    }

    @Override
    public List<SysElement> getLinkParentElementById(Long childId) {
        List<SysElement> parentElements = new ArrayList<>();
        Map<Long, SysElement> elementMap = new HashMap<>();
        List<SysElement> allElements = this.list();
        // 将所有元素放入map以便快速查找
        for (SysElement element : allElements) {
            elementMap.put(element.getId(), element);
        }
        // 递归查找所有父级元素
        while (childId != null && !Constant.Long_MINUS_ONE.equals(childId)) {
            SysElement currentElement = elementMap.get(childId);
            if (currentElement != null) {
                parentElements.add(currentElement);
                childId = currentElement.getParentId();
            } else {
                break;
            }
        }
        return parentElements;
    }

    @Override
    public List<SysElement> getLinkParentElementByList(List<Long> childIds) {
        List<SysElement> parentElements = new ArrayList<>();
        Set<Long> uniqueIds = new HashSet<>();
        Map<Long, SysElement> elementMap = new HashMap<>();
        List<SysElement> allElements = this.list();
        // 将所有元素放入map以便快速查找
        for (SysElement element : allElements) {
            elementMap.put(element.getId(), element);
        }
        // 递归查找所有父级元素，并确保不重复
        for (Long childId : childIds) {
            this.collectParentElements(childId, elementMap, parentElements, uniqueIds);
        }
        return parentElements;
    }

    /**
     * 获取指定元素及其所有子元素。
     * @param parentId 当前元素的父ID
     * @return 包含当前元素及其所有子元素的列表
     */
    @Override
    public List<SysElement> getLinkChildElementById(Long parentId) {
        List<SysElement> childElements = new ArrayList<>();
        List<SysElement> allElements = this.list();
        // 找到当前元素并添加到列表中
        SysElement currentElement = this.findElementById(parentId, allElements);
        if (currentElement != null) {
            childElements.add(currentElement);
            this.collectChildElements(currentElement, childElements, allElements);
        }
        return childElements;
    }

    @Override
    public List<SysElement> getLinkChildElementByList(List<Long> parentIds) {
        List<SysElement> childElements = new ArrayList<>();
        Set<Long> uniqueIds = new HashSet<>();
        List<SysElement> allElements = this.list();
        // 逐个处理每个父元素
        for (Long parentId : parentIds) {
            SysElement currentElement = this.findElementById(parentId, allElements);
            if (currentElement != null && !uniqueIds.contains(currentElement.getId())) {
                childElements.add(currentElement);
                uniqueIds.add(currentElement.getId());
                this.collectChildListElements(currentElement, childElements, allElements, uniqueIds);
            }
        }
        return childElements;
    }

    /**
     * 递归收集当前元素的所有子元素，并确保不重复。
     * @param parentElement
     * @param childElements
     * @param allElements
     * @param uniqueIds
     */
    private void collectChildListElements(SysElement parentElement, List<SysElement> childElements, List<SysElement> allElements, Set<Long> uniqueIds) {
        for (SysElement element : allElements) {
            if (ObjectUtil.equals(element.getParentId(), parentElement.getId()) && !uniqueIds.contains(element.getId())) {
                childElements.add(element);
                uniqueIds.add(element.getId());
                this.collectChildListElements(element, childElements, allElements, uniqueIds);
            }
        }
    }

    /**
     * 根据ID查找元素
     * @param id
     * @param elements
     * @return
     */
    private SysElement findElementById(Long id, List<SysElement> elements) {
        for (SysElement element : elements) {
            if (ObjectUtil.equals(element.getId(), id)) {
                return element;
            }
        }
        return null;
    }

    /**
     * 递归查找当前元素的所有子元素
     * @param parentElement
     * @param childElements
     * @param allElements
     */
    private void collectChildElements(SysElement parentElement, List<SysElement> childElements, List<SysElement> allElements) {
        for (SysElement element : allElements) {
            if (ObjectUtil.equals(element.getParentId(), parentElement.getId())) {
                childElements.add(element);
                this.collectChildElements(element, childElements, allElements);
            }
        }
    }

    /**
     * 递归查找所有父级元素，并确保不重复
     * @param childId
     * @param elementMap
     * @param parentElements
     * @param uniqueIds
     */
    private void collectParentElements(Long childId, Map<Long, SysElement> elementMap, List<SysElement> parentElements, Set<Long> uniqueIds) {
        while (childId != null && !Constant.Long_MINUS_ONE.equals(childId)) {
            SysElement currentElement = elementMap.get(childId);
            if (currentElement != null && !uniqueIds.contains(currentElement.getId())) {
                parentElements.add(currentElement);
                uniqueIds.add(currentElement.getId());
                childId = currentElement.getParentId();
            } else {
                break;
            }
        }
    }

    /**
     * 构建树形结构
     * @param elements
     * @return
     */
    public List<SysElementVO> buildElementTree(List<SysElementVO> elements) {
        // 先按sort字段排序，null值排在最后
        elements.sort(Comparator.comparing(SysElementVO::getSort,
                Comparator.nullsLast(Comparator.reverseOrder())));
        Map<Long, SysElementVO> elementMap = new HashMap<>();
        List<SysElementVO> rootNodes = new ArrayList<>();
        // 将所有元素放入map以便快速查找
        for (SysElementVO element : elements) {
            elementMap.put(element.getId(), element);
        }
        // 遍历所有元素，构建树形结构
        for (SysElementVO element : elements) {
            Long parentId = element.getParentId();
            // 如果没有父节点，则认为是根节点
            if (Constant.Long_MINUS_ONE.equals(parentId)) {
                rootNodes.add(element);
            } else {
                // 否则，尝试添加到其父节点的children列表中
                SysElementVO parent = elementMap.get(parentId);
                if (parent != null) {
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>());
                    }
                    parent.getChildren().add(element);
                }
            }
        }
        // 对每个节点的子节点进行排序
        this.sortChildrenRecursively(rootNodes);
        // 返回所有根节点组成的列表
        return rootNodes;
    }

    /**
     * 递归对子节点进行排序
     * @param nodes 需要排序的节点列表
     */
    private void sortChildrenRecursively(List<SysElementVO> nodes) {
        if (CollectionUtil.isEmpty(nodes)) {
            return;
        }
        for (SysElementVO node : nodes) {
            if (node.getChildren() != null && !node.getChildren().isEmpty()) {
                // 对当前节点的子节点按sort字段排序
                node.getChildren().sort(Comparator.comparing(SysElementVO::getSort,
                        Comparator.nullsLast(Comparator.reverseOrder())));
                // 递归处理下一级子节点
                this.sortChildrenRecursively(node.getChildren());
            }
        }
    }

    private LambdaQueryWrapper<SysElement> createWrapper(SysElementRequest sysElementRequest) {
        return new LambdaQueryWrapper<SysElement>()
                .like(!StringUtils.isEmpty(sysElementRequest.getElementName()), SysElement::getElementName, sysElementRequest.getElementName())
                .like(ObjectUtil.isNotEmpty(sysElementRequest.getElementType()), SysElement::getElementType, sysElementRequest.getElementType())
                .like(!StringUtils.isEmpty(sysElementRequest.getElementUrl()), SysElement::getElementUrl, sysElementRequest.getElementUrl())
                .like(!StringUtils.isEmpty(sysElementRequest.getElementPermit()), SysElement::getElementPermit, sysElementRequest.getElementPermit())
                .eq(ObjectUtil.isNotEmpty(sysElementRequest.getParentId()), SysElement::getParentId, sysElementRequest.getParentId())
                .orderByDesc(SysElement::getSort);
    }
}
